#include "graphic_particle_displayer_2d.h"

// .. REFERENCES

#include "primitives.h"
#include "debug.h"
#include "math.h"
#include "graphic_particle_displayer.h"
#include "graphic_particle_table.h"
#include "graphic_particle_system.h"
#include <cstdlib>

// -- PUBLIC

// .. CONSTRUCTORS

GRAPHIC_PARTICLE_DISPLAYER_2D::GRAPHIC_PARTICLE_DISPLAYER_2D() :
    GRAPHIC_PARTICLE_DISPLAYER()
{
}

// .. OPERATIONS

VOID GRAPHIC_PARTICLE_DISPLAYER_2D::Initialize(
    const TEXT & particle_texture,
    const GRAPHIC_PARTICLE_TABLE & particle_table
    )
{
    MaximumVertexCount = particle_table.GetParticleCount() * 6;

    GRAPHIC_PARTICLE_DISPLAYER::Initialize( particle_texture, particle_table );
}

// ~~

VOID GRAPHIC_PARTICLE_DISPLAYER_2D::Render(
    const GRAPHIC_PARTICLE_TABLE & particle_table
    )
{
    UpdateVertexBuffer( particle_table );

    if ( CurrentVertexCount )
    {

    	ParticleTexture->BindTexture();
        ParticleShader->Enable();


        GRAPHIC_VERTEX_BUFFER::EnableVertexArray( ( REAL * ) VertexTable.GetArray(), 2, sizeof( VERTEX ) );
        GRAPHIC_VERTEX_BUFFER::EnableTexCoordArray( ( REAL * ) & VertexTable[0].UV , 2, sizeof( VERTEX ) );
        //GRAPHIC_VERTEX_BUFFER::EnableVertexArray( ( REAL * ) VertexTable.GetArray(), 2, sizeof( VERTEX ) );

        GRAPHIC_VERTEX_BUFFER::Draw( CurrentVertexCount );

        ParticleShader->Disable();
    }
}

// -- PRIVATE

// .. OPERATIONS

VOID GRAPHIC_PARTICLE_DISPLAYER_2D::UpdateVertexBuffer(
    const GRAPHIC_PARTICLE_TABLE & particle_table
    )
{
    ARRAY< VERTEX >
        & vertex_table = VertexTable;
    COUNT
        vertex_count,
        particle_count,
        final_particle_count;
    INDEX
        table_index,
        particle_index;
    REAL
        position_x,
        position_y,
        half_size_x,
        half_size_y,
        cos_rotation,
        sin_rotation;
    UINT32
        color;

    //VertexBuffer.Swap();

    vertex_table.SetItemCount( MaximumVertexCount );
    final_particle_count = 0;

    for_each_table_index( table_index , particle_table.GetParticleTable() )
    {
    	for_each_index( particle_index, GRAPHIC_PARTICLE_TABLE::FixedParticleCount )
        {
            if ( particle_table.GetParticleTable()[ table_index ].Enabled[ particle_index ] )
            {
                half_size_x = particle_table.GetParticleTable()[ table_index ].Extent[ particle_index ].X * 0.5f ;
                half_size_y = particle_table.GetParticleTable()[ table_index ].Extent[ particle_index ].Y * 0.5f ;
                position_x = particle_table.GetParticleTable()[ table_index ].Position[ particle_index ].X;
                position_y = particle_table.GetParticleTable()[ table_index ].Position[ particle_index ].Y;

                vertex_table[ final_particle_count * 6 + 0 ].Position.X = position_x - half_size_x;
                vertex_table[ final_particle_count * 6 + 0 ].Position.Y = position_y + half_size_y;
                vertex_table[ final_particle_count * 6 + 1 ].Position.X = position_x + half_size_x;
                vertex_table[ final_particle_count * 6 + 1 ].Position.Y = position_y + half_size_y;
                vertex_table[ final_particle_count * 6 + 2 ].Position.X = position_x + half_size_x;
                vertex_table[ final_particle_count * 6 + 2 ].Position.Y = position_y - half_size_y;

                vertex_table[ final_particle_count * 6 + 3 ].Position = vertex_table[ final_particle_count * 6 + 2 ].Position;
                vertex_table[ final_particle_count * 6 + 4 ].Position.X = position_x - half_size_x;
                vertex_table[ final_particle_count * 6 + 4 ].Position.Y = position_y - half_size_y;
                vertex_table[ final_particle_count * 6 + 5 ].Position = vertex_table[ final_particle_count * 6 + 0 ].Position;

                vertex_table[ final_particle_count * 6 + 0 ].UV.Set( 0.0f, 0.0f );
                vertex_table[ final_particle_count * 6 + 1 ].UV.Set( 1.0f, 0.0f );
                vertex_table[ final_particle_count * 6 + 2 ].UV.Set( 1.0f, 1.0f );
                vertex_table[ final_particle_count * 6 + 3 ].UV.Set( 1.0f, 1.0f );
                vertex_table[ final_particle_count * 6 + 4 ].UV.Set( 0.0f, 1.0f );
                vertex_table[ final_particle_count * 6 + 5 ].UV.Set( 0.0f, 0.0f );

                color = 0;
                //color = particle_table.GetParticleTable()[ table_index ].Color[ particle_index ].GetRGBAIntegerColor();

                vertex_table[ final_particle_count * 6 + 0 ].Color = color;
                vertex_table[ final_particle_count * 6 + 1 ].Color = color;
                vertex_table[ final_particle_count * 6 + 2 ].Color = color;
                vertex_table[ final_particle_count * 6 + 3 ].Color = color;
                vertex_table[ final_particle_count * 6 + 4 ].Color = color;
                vertex_table[ final_particle_count * 6 + 5 ].Color = color;

                final_particle_count ++;

                if ( final_particle_count >= particle_table.GetParticleCount() )
                {
                    break ;
                }
            }
        }
    }

    particle_count = 0;

    if( Flags & GRAPHIC_PARTICLE_SYSTEM::FLAG_UseOrientation )
    {
    	for_each_table_index( table_index , particle_table.GetParticleTable() )
        {
    		for_each_index( particle_index, GRAPHIC_PARTICLE_TABLE::FixedParticleCount )
            {
                if ( particle_table.GetParticleTable()[ table_index ].Enabled[ particle_index ] )
                {
                    half_size_x = particle_table.GetParticleTable()[ table_index ].Extent[ particle_index ].X * 0.5f ;
                    half_size_y = particle_table.GetParticleTable()[ table_index ].Extent[ particle_index ].Y * 0.5f ;
                    position_x = particle_table.GetParticleTable()[ table_index ].Position[ particle_index ].X;
                    position_y = particle_table.GetParticleTable()[ table_index ].Position[ particle_index ].Y;

                    cos_rotation = MATH_GetCosinus( particle_table.GetParticleTable()[ table_index ].Angle[ particle_index ] );
                    sin_rotation = MATH_GetSinus( particle_table.GetParticleTable()[ table_index ].Angle[ particle_index ] );

                    vertex_table[ particle_count * 6 + 0 ].Position.X = position_x + cos_rotation * half_size_x + sin_rotation * -half_size_y;
                    vertex_table[ particle_count * 6 + 0 ].Position.Y = position_y + -sin_rotation * half_size_x + cos_rotation * -half_size_y;
                    vertex_table[ particle_count * 6 + 1 ].Position.X = position_x + cos_rotation * -half_size_x + sin_rotation * -half_size_y;
                    vertex_table[ particle_count * 6 + 1 ].Position.Y = position_y + -sin_rotation * -half_size_x + cos_rotation * -half_size_y;
                    vertex_table[ particle_count * 6 + 2 ].Position.X = position_x + cos_rotation * -half_size_x + sin_rotation * half_size_y;
                    vertex_table[ particle_count * 6 + 2 ].Position.Y = position_y + -sin_rotation * -half_size_x + cos_rotation * half_size_y;

                    vertex_table[ particle_count * 6 + 3 ].Position = vertex_table[ particle_count * 6 + 2 ].Position;
                    vertex_table[ particle_count * 6 + 4 ].Position.X = position_x + cos_rotation * half_size_x + sin_rotation * half_size_y;
                    vertex_table[ particle_count * 6 + 4 ].Position.Y = position_y + -sin_rotation * half_size_x + cos_rotation * half_size_y;
                    vertex_table[ particle_count * 6 + 5 ].Position = vertex_table[ particle_count * 6 + 0 ].Position;

                    particle_count ++;

                    if ( particle_count >= final_particle_count )
                    {
                        break ;
                    }
                }
            }
        }
    }

    vertex_count = CurrentVertexCount = final_particle_count * 6;

    if ( !vertex_count )
    {
        return;
    }

    DEBUG_Require( vertex_count <= MaximumVertexCount );

    //VertexBuffer.SetVertexCount( vertex_count );
    //vertex_buffer_pointer = VertexBuffer.Lock();
    //memcpy( vertex_buffer_pointer, vertex_table.GetArray(), sizeof( VERTEX ) * vertex_count );
    //VertexBuffer.Unlock();

}
